package com.middleware.mvc.context;

import com.middleware.mvc.annotations.Controller;
import com.middleware.spring.annotations.*;
import com.middleware.spring.beanDefinition.BeanDefinition;
import com.middleware.spring.context.ApplicationContext;
import com.middleware.spring.processers.BeanPostProcessor;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.beans.Introspector;
import java.io.File;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.util.List;
import java.util.Map;

public class WebApplicationContext extends ApplicationContext {
    private static final Logger log = LoggerFactory.getLogger(WebApplicationContext.class);


    private ApplicationContext parentApplicationContext =  null;
    public WebApplicationContext(Class<?> configClass) {
        super(configClass);
    }


    public WebApplicationContext(String path) {
        super(path);
    }

    public WebApplicationContext(String path,ApplicationContext applicationContext){
        super();
        this.parentApplicationContext = applicationContext;
        scanBeans(path);
        instantiateBeans();

    }

    public void setParentApplicationContext(ApplicationContext parentApplicationContext) {
        this.parentApplicationContext = parentApplicationContext;
    }

    protected void scanBeans(String path) {

        List<Class<?>> beanClassList = getBeanClassFromPackage(path);
        for (Class<?> clazz : beanClassList) {
            //如果实现了 BeanPostProcessor 接口
            if (BeanPostProcessor.class.isAssignableFrom(clazz)) {
                BeanPostProcessor beanPostProcessor = null;
                try {
                    beanPostProcessor = (BeanPostProcessor) clazz.getConstructor().newInstance();
                } catch (InstantiationException |
                         IllegalAccessException |
                         InvocationTargetException |
                         NoSuchMethodException e) {
                    throw new RuntimeException(e);
                }
                beanPostProcessorList.add(beanPostProcessor);
            }else {
                //如果是普通类
                BeanDefinition beanDefinition = new BeanDefinition();
                beanDefinition.setBeanClass(clazz);
                beanDefinition.setLazy(false);
                beanDefinition.setScope(SINGLETON);
                if(clazz.isAnnotationPresent(Lazy.class)){
                    beanDefinition.setLazy(true);
                }
                if(clazz.isAnnotationPresent(Scope.class)){
                    beanDefinition.setScope(clazz.getAnnotation(Scope.class).value());
                }

                //生成 beanName
                //spring底层自动生成beanname
                String beanName = Introspector.decapitalize(clazz.getSimpleName());
                Component annotation = clazz.getAnnotation(Component.class);
                if (annotation != null) {
                    String value = annotation.value();
                    if(!"".equals(value)){
                        beanName = value;
                    }
                }else if(clazz.isAnnotationPresent(Service.class)){
                    String value = clazz.getAnnotation(Service.class).value();
                    if(!"".equals(value)){
                        beanName = value;
                    }
                }
                beanDefinitionMap.put(beanName, beanDefinition);
            }
        }

    }

//    @Override
//    public Object getBean(String fieldName) {
//        //先从 单例池中获取
//        Object bean = singletonObjects.get(fieldName);
//        if (bean != null) {
//                return bean;
//        }
//        bean = parentApplicationContext.getBean(fieldName);
//        if(bean != null){
//            return bean;
//        }
//        bean = instantiateBeans(fieldName);
//
//        BeanDefinition beanDefinition = beanDefinitionMap.get(fieldName);
//
//        if(beanDefinition.getScope().equals(SINGLETON)){
//            singletonObjects.put(fieldName, bean);
//        }
//
//        return bean;
//    }

    public Object getBean(Class<?> clazz) {
        String beanName = Introspector.decapitalize(clazz.getSimpleName());
        Object bean = getBean(beanName);
        if(bean == null){
            //启动按照类型注入
            //遍历所有的BeanDefinition
            for (Map.Entry<String, BeanDefinition> entry : beanDefinitionMap.entrySet()) {
                BeanDefinition beanDefinition = entry.getValue();
                //如果 clazz 是 beanClass 的父类
                if (clazz.isAssignableFrom(beanDefinition.getBeanClass())) {
                    beanName = Introspector.decapitalize(beanDefinition.getBeanClass().getSimpleName());
                    bean = getBean(beanName);
                    break;
                }
            }
        }
        if(bean == null){
            bean = parentApplicationContext.getBean(clazz);
        }
        return bean;
    }


//    protected void populateBean(Object bean, Class<?> beanClass) {
//        for(Field field : beanClass.getDeclaredFields()) {
//            if (field.isAnnotationPresent(Autowired.class)) {
//                Class<?> fieldType = field.getType();
//                Object fieldValue = this.getBean(fieldType);
//                field.setAccessible(true);
//
//                try {
//                    field.set(bean, fieldValue);
//                } catch (IllegalAccessException var11) {
//                }
//            }
//        }
//
//    }

    /**
     * 处理类文件并检查注解
     */
    protected void processClassFile(File classFile, String currentPackage,
                                    List<Class<?>> beanClassList, ClassLoader classLoader) {
        try {
            // 获取简单类名（去掉.class后缀）
            String className = classFile.getName().replace(".class", "");
            // 构建完整类名
            String fullClassName = currentPackage + "." + className;

            // 排除内部类
            if (className.contains("$")) {
                return;
            }

            Class<?> clazz = classLoader.loadClass(fullClassName);
            if (clazz.isAnnotationPresent(Component.class) ||
                    clazz.isAnnotationPresent(Service.class)
            || clazz.isAnnotationPresent(Controller.class)) {
                beanClassList.add(clazz);
            }
        } catch (ClassNotFoundException e) {
            log.error("加载类失败: {}", classFile.getName(), e);
        } catch (NoClassDefFoundError e) {
            log.warn("类定义不完整: {}, 错误: {}", classFile.getName(), e.getMessage());
        }
    }
}
